package lg.minecraft.plugin.pokemonmenu;

import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.api.storage.party.PartyPosition;
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore;
import com.cobblemon.mod.common.api.storage.pc.PCBox;
import com.cobblemon.mod.common.api.storage.pc.PCPosition;
import com.cobblemon.mod.common.api.storage.pc.PCStore;
import com.cobblemon.mod.common.battles.BattleRegistry;
import com.cobblemon.mod.common.pokemon.Pokemon;
import lg.minecraft.plugin.cobblemoncore.util.BukkitNmsConverter;
import lg.minecraft.plugin.library.inventory.LGInventory;
import lg.minecraft.plugin.pokemonmenu.config.MainConfig;
import lg.minecraft.plugin.pokemonmenu.util.Position;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import net.minecraft.class_5455;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;

import java.util.Objects;
import java.util.UUID;

/**
 * @author langle__
 * @version 1.0
 */
@Getter
public class PokemonPlayer {

    private static final int POKEMON_PER_BOX = 30;

    private final UUID uuid;

    @Setter private boolean openWildPokemon = false;
    @Setter private boolean viewPlayerParty = false;
    @Setter private boolean autoHeal = false;
    @Setter private boolean disabledView = false;
    @Setter private boolean editMode = false;

    @Setter private LGInventory previousInventory = null;

    public PokemonPlayer(@NonNull UUID uuid) {
        this.uuid = uuid;
    }

    public PokemonPlayer(@NonNull OfflinePlayer player) {
        this.uuid = player.getUniqueId();
    }

    public PokemonPlayer(@NonNull Player player) {
        this.uuid = player.getUniqueId();
        if (!player.isOnline()) return;
        MainConfig mainConfig = LGPokemonMenu.getMainConfig();
        this.autoHeal = mainConfig.isDefaultAutoHeal() && player.hasPermission("LGPokemonMenu.auto_heal");
        this.disabledView = mainConfig.isDefaultDisabledView() && player.hasPermission("LGPokemonMenu.disabled_view");
        this.openWildPokemon = mainConfig.isDefaultOpenWildPokemon() && player.hasPermission("LGPokemonMenu.open_wild_pokemon");
        this.viewPlayerParty = mainConfig.isDefaultViewPlayerParty() && player.hasPermission("LGPokemonMenu.view_player_party");
    }

    /**
     * 判断玩家是否正在参与战斗。
     *
     * @return 如果玩家正在战斗中返回 true，否则返回 false。
     */
    public boolean isInBattle() {
        return BattleRegistry.getBattleByParticipatingPlayerId(this.uuid) != null;
    }

    /**
     * 判断上一个存库是否为 null。
     *
     * @return 如果 previousInventory 为 null，则返回 true；否则返回 false。
     */
    public boolean isPreviousInventoryEmpty() {
        return previousInventory == null;
    }

    public boolean removePokemon(int slot) {
        return getPartyStore().remove(new PartyPosition(slot));
    }

    public boolean removePokemon(int box, int slot) {
        return getPCStore().remove(new PCPosition(box, slot));
    }

    public void setPokemon(int slot, Pokemon pokemon) {
        getPartyStore().set(new PartyPosition(slot), pokemon);
    }

    public void setPokemon(int box, int slot, Pokemon pokemon) {
        getPCStore().set(new PCPosition(box, slot), pokemon);
    }

    public void setPokemon(PCPosition position, Pokemon pokemon) {
        getPCStore().set(position, pokemon);
    }

    public void setPokemon(PartyPosition position, Pokemon pokemon) {
        getPartyStore().set(position, pokemon);
    }

    public void setPokemon(Position position, Pokemon pokemon) {
        if (pokemon == null) return;
        if (position.isParty()) {
            getPartyStore().set(new PartyPosition(position.getSlot()), pokemon);
        } else {
            getPCStore().set(new PCPosition(position.getBox(), position.getSlot()), pokemon);
        }
    }

    public Pokemon getPartyPokemon(int slot) {
        return getPartyStore().get(slot);
    }

    public Pokemon getPCPokemon(int box, int slot) {
        return getPCStore().get(new PCPosition(box, slot));
    }

    public boolean addPartyPokemon(Pokemon pokemon) {
        return getPartyStore().add(pokemon);
    }

    public boolean addPCPokemon(Pokemon pokemon) {
        return getPCStore().add(pokemon);
    }

    public PlayerPartyStore getPartyStore() {
        class_5455 registryAccess = BukkitNmsConverter.getRegistryAccess();
        return Cobblemon.INSTANCE.getStorage().getParty(uuid, registryAccess);
    }

    public PCStore getPCStore() {
        class_5455 registryAccess = BukkitNmsConverter.getRegistryAccess();
        return Cobblemon.INSTANCE.getStorage().getPC(uuid, registryAccess);
    }

    public int getPcBoxSize() {
        return getPCStore().getBoxes().size();
    }

    public Pokemon getPokemon(Position position) {
        int box = position.getBox();
        int slot = position.getSlot();
        if (box < 0) {
            return getPartyPokemon(slot);
        }
        return getPCPokemon(box, slot);
    }

    public void removePokemon(Position position) {
        int box = position.getBox();
        int slot = position.getSlot();
        if (box < 0) {
            removePokemon(slot);
            return;
        }
        removePokemon(box, slot);
    }

    /**
     * 获取当前队伍的一个空缺位置。
     *
     * @return 返回一个空缺的队伍槽位索引，如果没有空缺则返回 -1
     */
    public Position getEmptyPartySlot() {
        PlayerPartyStore store = getPartyStore();
        for (int slot = 0; slot < 6; slot++) { // 队伍通常有 6 个槽位
            if (store.get(slot) == null) {
                return new Position(slot);
            }
        }
        return null;
    }

    /**
     * 获取 PC 某一页的第一个空槽位。
     *
     * @param page 页码（从 0 开始）
     * @return 返回第一个空槽位的索引，如果没有空槽位则返回 -1
     */
    public Position getEmptyPCSlot(int page) {
        PCBox pcBox = getPCStore().getBoxes().get(page);

        for (int slot = 0; slot < POKEMON_PER_BOX; slot++) {
            if (pcBox.get(slot) == null) {
                return new Position(page, slot);
            }
        }

        return null;
    }

    public void swap(Position pos1, Position pos2) {
        Pokemon p1 = getPokemon(pos1);
        Pokemon p2 = getPokemon(pos2);

        removePokemon(pos1);
        removePokemon(pos2);

        setPokemon(pos1, p2);
        setPokemon(pos2, p1);
    }

    @Override
    public boolean equals(Object object) {
        if (this == object) return true;
        if (object == null || getClass() != object.getClass()) return false;
        PokemonPlayer that = (PokemonPlayer) object;
        return Objects.equals(getUuid(), that.getUuid());
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(getUuid());
    }

}
